<template>
  <div class="comment-image-upload">
    <!-- 图片预览区域 -->
    <div v-if="imageList.length > 0" class="image-preview-grid">
      <div
        v-for="(image, index) in imageList"
        :key="image.id || image.tempId"
        class="image-preview-item"
      >
        <div class="image-wrapper">
          <img
            :src="image.previewUrl || formatImageUrl(image.fileUrl)"
            :alt="image.originalName"
            class="preview-image"
            @click="previewImage(index)"
          />

          <!-- 上传进度 -->
          <div v-if="image.uploading" class="upload-progress">
            <el-progress
              :percentage="image.progress"
              :show-text="false"
              :stroke-width="3"
            />
            <span class="progress-text">{{ image.progress }}%</span>
          </div>

          <!-- 删除按钮 -->
          <div class="image-actions">
            <el-button
              type="danger"
              size="small"
              circle
              :disabled="image.uploading"
              @click="removeImage(index)"
            >
              <el-icon><Close /></el-icon>
            </el-button>
          </div>

          <!-- 上传失败标识 -->
          <div v-if="image.error" class="upload-error">
            <el-icon><Warning /></el-icon>
            <span class="error-text">上传失败</span>
          </div>
        </div>
      </div>
    </div>

    <!-- 上传按钮 -->
    <div v-if="canAddMore" class="upload-trigger">
      <el-upload
        ref="uploadRef"
        :auto-upload="false"
        :show-file-list="false"
        :accept="acceptTypes"
        :multiple="true"
        :limit="maxImages"
        @change="handleFileChange"
        @exceed="handleExceed"
      >
        <div class="upload-button">
          <el-icon class="upload-icon"><Plus /></el-icon>
          <span class="upload-text">添加图片</span>
        </div>
      </el-upload>
    </div>

    <!-- 图片预览对话框 -->
    <el-dialog
      v-model="previewVisible"
      title="图片预览"
      width="80%"
      :before-close="closePreview"
    >
      <div class="image-preview-dialog">
        <img
          v-if="currentPreviewImage"
          :src="currentPreviewImage.previewUrl || currentPreviewImage.fileUrl"
          :alt="currentPreviewImage.originalName"
          class="preview-dialog-image"
        />
      </div>
    </el-dialog>

    <!-- 提示信息 -->
    <div class="upload-tips">
      <span class="tip-text">
        支持 JPG、PNG、GIF、WebP 格式，单张图片不超过 10MB，最多
        {{ maxImages }} 张
      </span>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { Plus, Close, Warning } from "@element-plus/icons-vue";
import type { UploadFile, UploadFiles } from "element-plus";
import {
  generateUploadTokenApi,
  uploadCommentImageApi,
  CommentImageUtils,
  type CommentImageInfo
} from "@/api/comment-image";
import { FileUploadType, UnifiedFileUploadUtils } from "@/api/unified-upload";
import { formatImageUrl } from "@/utils/avatar";

// Props定义
interface Props {
  /** 最大图片数量 */
  maxImages?: number;
  /** 是否禁用 */
  disabled?: boolean;
  /** 初始图片列表 */
  initialImages?: CommentImageInfo[];
}

const props = withDefaults(defineProps<Props>(), {
  maxImages: 9,
  disabled: false,
  initialImages: () => []
});

// Emits定义
const emit = defineEmits<{
  change: [images: ImageItem[]];
  upload: [image: ImageItem];
  remove: [image: ImageItem];
  error: [error: string];
}>();

// 图片项接口
interface ImageItem extends Partial<CommentImageInfo> {
  tempId?: string;
  file?: File;
  previewUrl?: string;
  uploading?: boolean;
  progress?: number;
  error?: boolean;
  uploadToken?: string;
}

// 响应式数据
const uploadRef = ref();
const imageList = ref<ImageItem[]>([]);
const uploadToken = ref<string>("");
const previewVisible = ref(false);
const currentPreviewImage = ref<ImageItem | null>(null);

// 计算属性
const acceptTypes = computed(() => {
  return CommentImageUtils.SUPPORTED_FORMATS.join(",");
});

const canAddMore = computed(() => {
  return !props.disabled && imageList.value.length < props.maxImages;
});

// 初始化图片列表
watch(
  () => props.initialImages,
  newImages => {
    if (newImages && newImages.length > 0) {
      imageList.value = newImages.map(img => ({
        ...img,
        uploading: false,
        error: false
      }));
    }
  },
  { immediate: true }
);

// 生成上传令牌
const generateUploadToken = async (): Promise<string> => {
  if (uploadToken.value) {
    return uploadToken.value;
  }

  try {
    const response = await generateUploadTokenApi();
    if (response.code === 200 && response.data) {
      uploadToken.value = response.data;
      return response.data;
    } else {
      throw new Error(response.message || "生成上传令牌失败");
    }
  } catch (error) {
    console.error("生成上传令牌失败:", error);
    throw error;
  }
};

// 处理文件选择
const handleFileChange = async (file: UploadFile, files: UploadFiles) => {
  const newFiles = files.slice(-1); // 只处理最新选择的文件

  for (const uploadFile of newFiles) {
    if (!uploadFile.raw) continue;

    // 验证文件
    const validation = CommentImageUtils.validateImageFile(uploadFile.raw);
    if (!validation.valid) {
      ElMessage.error(validation.message);
      continue;
    }

    // 检查数量限制
    const limitCheck = CommentImageUtils.checkImageLimit(
      imageList.value.length,
      1
    );
    if (!limitCheck.valid) {
      ElMessage.error(limitCheck.message);
      break;
    }

    // 创建图片项
    const imageItem: ImageItem = {
      tempId: `temp_${Date.now()}_${Math.random()}`,
      file: uploadFile.raw,
      originalName: uploadFile.name,
      fileSize: uploadFile.raw.size,
      contentType: uploadFile.raw.type,
      previewUrl: CommentImageUtils.generatePreviewUrl(uploadFile.raw),
      uploading: true,
      progress: 0,
      error: false
    };

    // 添加到列表
    imageList.value.push(imageItem);

    // 开始上传
    uploadImage(imageItem);
  }

  // 清空文件选择
  uploadRef.value?.clearFiles();
};

// 上传图片
const uploadImage = async (imageItem: ImageItem) => {
  if (!imageItem.file) return;

  try {
    // 先使用统一工具进行文件验证
    const validation = UnifiedFileUploadUtils.validateFile(
      imageItem.file!,
      FileUploadType.COMMENT_IMAGE
    );
    if (!validation.valid) {
      throw new Error(validation.message || "文件验证失败");
    }

    // 生成上传令牌
    const token = await generateUploadToken();
    imageItem.uploadToken = token;

    // 模拟上传进度
    const progressInterval = setInterval(() => {
      if (imageItem.progress! < 90) {
        imageItem.progress = (imageItem.progress || 0) + 10;
      }
    }, 100);

    // 上传文件
    const response = await uploadCommentImageApi(imageItem.file, token);

    clearInterval(progressInterval);

    if (response.code === 200 && response.data) {
      // 上传成功
      imageItem.progress = 100;
      imageItem.uploading = false;

      // 更新图片信息
      Object.assign(imageItem, response.data.imageInfo);
      imageItem.id = response.data.tempImageId;

      emit("upload", imageItem);
      ElMessage.success("图片上传成功");
    } else {
      throw new Error(response.message || "图片上传失败");
    }
  } catch (error) {
    console.error("图片上传失败:", error);

    imageItem.uploading = false;
    imageItem.error = true;
    imageItem.progress = 0;

    const errorMessage = CommentImageUtils.formatErrorMessage(error);
    emit("error", errorMessage);
    ElMessage.error(errorMessage);
  }
};

// 移除图片
const removeImage = async (index: number) => {
  const imageItem = imageList.value[index];

  if (imageItem.uploading) {
    ElMessage.warning("图片正在上传中，请稍后再试");
    return;
  }

  try {
    await ElMessageBox.confirm("确定要删除这张图片吗？", "确认删除", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning"
    });

    // 释放预览URL
    if (imageItem.previewUrl) {
      CommentImageUtils.revokePreviewUrl(imageItem.previewUrl);
    }

    // 从列表中移除
    imageList.value.splice(index, 1);

    emit("remove", imageItem);
    emit("change", imageList.value);
  } catch {
    // 用户取消删除
  }
};

// 处理文件数量超限
const handleExceed = () => {
  ElMessage.warning(`最多只能上传 ${props.maxImages} 张图片`);
};

// 预览图片
const previewImage = (index: number) => {
  currentPreviewImage.value = imageList.value[index];
  previewVisible.value = true;
};

// 关闭预览
const closePreview = () => {
  previewVisible.value = false;
  currentPreviewImage.value = null;
};

// 监听图片列表变化
watch(
  imageList,
  newList => {
    emit("change", newList);
  },
  { deep: true }
);

// 暴露方法给父组件
defineExpose({
  getImages: () => imageList.value,
  getUploadToken: () => uploadToken.value,
  clearImages: () => {
    imageList.value.forEach(item => {
      if (item.previewUrl) {
        CommentImageUtils.revokePreviewUrl(item.previewUrl);
      }
    });
    imageList.value = [];
  }
});
</script>

<style scoped lang="scss">
// 移动端适配
@media (width <= 768px) {
  .comment-image-upload {
    .image-preview-grid {
      grid-template-columns: repeat(auto-fill, minmax(60px, 1fr));
      gap: 6px;
    }

    .upload-trigger {
      .upload-button {
        width: 60px;
        height: 60px;

        .upload-icon {
          font-size: 16px;
        }

        .upload-text {
          font-size: 10px;
        }
      }
    }
  }
}

.comment-image-upload {
  .image-preview-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
    gap: 8px;
    margin-bottom: 12px;

    .image-preview-item {
      position: relative;
      aspect-ratio: 1;
      overflow: hidden;
      background: #f8f9fa;
      border: 1px solid #e4e6ea;
      border-radius: 6px;

      .image-wrapper {
        position: relative;
        width: 100%;
        height: 100%;

        .preview-image {
          width: 100%;
          height: 100%;
          cursor: pointer;
          object-fit: cover;
          transition: transform 0.2s ease;

          &:hover {
            transform: scale(1.05);
          }
        }

        .upload-progress {
          position: absolute;
          right: 0;
          bottom: 0;
          left: 0;
          padding: 4px 8px;
          font-size: 12px;
          color: white;
          background: rgb(0 0 0 / 70%);

          .progress-text {
            display: block;
            margin-top: 2px;
            text-align: center;
          }
        }

        .image-actions {
          position: absolute;
          top: 4px;
          right: 4px;
          opacity: 0;
          transition: opacity 0.2s ease;

          .el-button {
            width: 20px;
            height: 20px;
            min-height: 20px;
            padding: 0;
            background: rgb(0 0 0 / 60%);
            border: none;

            .el-icon {
              font-size: 12px;
            }
          }
        }

        .upload-error {
          position: absolute;
          inset: 0;
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          font-size: 12px;
          color: #ff4757;
          background: rgb(255 0 0 / 10%);

          .el-icon {
            margin-bottom: 2px;
            font-size: 16px;
          }
        }

        &:hover .image-actions {
          opacity: 1;
        }
      }
    }
  }

  .upload-trigger {
    .upload-button {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      width: 80px;
      height: 80px;
      cursor: pointer;
      background: #fafafa;
      border: 2px dashed #d9d9d9;
      border-radius: 6px;
      transition: all 0.2s ease;

      &:hover {
        background: #f0f8ff;
        border-color: #1e80ff;

        .upload-icon {
          color: #1e80ff;
        }
      }

      .upload-icon {
        margin-bottom: 4px;
        font-size: 20px;
        color: #8a919f;
      }

      .upload-text {
        font-size: 12px;
        color: #8a919f;
      }
    }
  }

  .upload-tips {
    margin-top: 8px;

    .tip-text {
      font-size: 12px;
      line-height: 1.4;
      color: #8a919f;
    }
  }
}

.image-preview-dialog {
  text-align: center;

  .preview-dialog-image {
    max-width: 100%;
    max-height: 70vh;
    object-fit: contain;
  }
}

// 暗色主题适配
.dark {
  .comment-image-upload {
    .image-preview-grid {
      .image-preview-item {
        background: #2a2a3a;
        border-color: #3a3a4a;
      }
    }

    .upload-trigger {
      .upload-button {
        background: #2a2a3a;
        border-color: #3a3a4a;

        &:hover {
          background: #1a1a2e;
          border-color: #1e80ff;
        }

        .upload-icon,
        .upload-text {
          color: #86909c;
        }
      }
    }

    .upload-tips {
      .tip-text {
        color: #86909c;
      }
    }
  }
}
</style>
